package echiquier;

import java.util.Iterator;
import echiquier.Curseur.EtatCurseur;
import echiquier.Echiquier.Case;
import echiquier.Echiquier.Ligne;

/**
 *
 * @author me
 */
public final class Echiquier {

    /**
     * valeur de case hors de l'echiquier
     */
    public static final int HORS_JEU = -1;
    /**
     *pour l'echiquier englobant (la table)
     */
    public static final int NbRangsTable = 12;
    /**
     *pour l'echiquier englobant (la table)
     */
    public static final int NbColonnesTable = 10;
    /**
     *echiquier ordinnaire (englobé)
     */
    public static final int DimEchiquier = 8;
    /**
     *index de la première case de la table
     */
    public static final int IndexInitial = 21;
    /**
     *index de la derniere case de la table
     */
    public static final int IndexFinal = 98;
    /**
     * CASES , la table ou echiquier englobant divisé en 120 "cases"
     */
    private final static int[] CASES;
    private static Echiquier instance = new Echiquier();


    static {
        CASES = new int[NbRangsTable * NbColonnesTable];
        for (int i = 0; i < 120; i++) {
            CASES[i] = HORS_JEU;
        }

        int valeur = 0;
        for (int index = IndexInitial; index <= IndexFinal; index++) {
            if (index % NbColonnesTable == DimEchiquier) {
                CASES[index] = valeur++;
                index += 2;
            } else {
                CASES[index] = valeur++;
            }
        }
    }

    /**
     *Constructeur privé
     */
    private Echiquier() {
    }

    /**
     *
     * @return instance unique de l'échiquier
     */
    public final static Echiquier getInstance() {
        return instance;
    }

    public final Iterator<EtatCurseur> iterateur() {
        return new Curseur().parcours().iterator();
    }

    /**
     *Echiquier intuitif
     */
    public enum Case {

        a1, b1, c1, d1, e1, f1, g1, h1,
        a2, b2, c2, d2, e2, f2, g2, h2,
        a3, b3, c3, d3, e3, f3, g3, h3,
        a4, b4, c4, d4, e4, f4, g4, h4,
        a5, b5, c5, d5, e5, f5, g5, h5,
        a6, b6, c6, d6, e6, f6, g6, h6,
        a7, b7, c7, d7, e7, f7, g7, h7,
        a8, b8, c8, d8, e8, f8, g8, h8;
        private static int index;

        /**
         *
         * @return case suivante d'après un index interne
         */
        public static Case next() {
            assert index >= 0;
            return values()[index++];
        }
    }

    /**
     *fonction utilitaire de conversion Case -- int
     * @param nom de la case (a1,a2 ...)
     * @return sa valeur dans l'echiquier intuitif
     */
    public final static int valeur(final Case nom) {
        assert nom != null;
        return (nom.ordinal() / 8) * 2 + nom.ordinal() + 21;

    }

    /**
     *fonction utilitaire de conversion int -- Case
     * @param index valeur dans l'echiquier intuitif
     * @return case de l'echiquier intuitif
     */
    public final static Case nom(final int index) {
        assert index >= 0;
        return Case.values()[index % 10 - 1 + 8 * (index / 10 - 2)];
    }

    /**
     *
     * @param CaseCandidate pour un coups 
     * @param ligne courante (direction de deplacement)
     * @return true si le curseur sort de l'échiquier
     */
    public final static boolean hasnext(final Case CaseCandidate, final Ligne ligne) {
        assert ligne != null;
        return CASES[valeur(CaseCandidate) + ligne.val] == HORS_JEU;
    }

    /**
     *
     * @param CaseCandidate pour un coups
     * @param ligne ligne courante (direction de deplacement)
     * @return case next de la case candidate dans la direction ligne
     */
    public final static Case suivant(final Case CaseCandidate, final Ligne ligne) {
        return nom(valeur(CaseCandidate) + ligne.val);
    }

    /**
     *definition des deplacements aux echecs avec valeurs pour la table
     * ou echiquier "englobant"
     */
    public enum Ligne {

        nord(10),
        nord_nord_est(21),
        nord_est(11),
        nord_est_est(12),
        est(1),
        sud_est_est(-8),
        sud_est(-9),
        sud_sud_est(-19),
        sud(-10),
        sud_sud_ouest(-21),
        sud_ouest(-11),
        sud_ouest_ouest(-12),
        ouest(-1),
        nord_ouest_ouest(8),
        nord_ouest(9),
        nord_nord_ouest(19);
        private static int index;
        private int val;

        /**
         * valeur du deplacement (int) pour le grand echiquier
         * @param val
         */
        private Ligne(final int val) {
            this.val = val;
        }

        /**
         *direction next
         * @return direction next
         */
        public static Ligne next() {
            assert index >= 0;
            return values()[index++];
        }

        /**
         *
         * @param ligne
         * @return true si toutes les directions sont explorées
         */
        public static boolean hasnext(final Ligne ligne) {
            boolean fin = false;
            if (ligne == nord_nord_ouest) {
                index = 0;
                fin = true;
            }
            return fin;
        }

        /**
         *valeur du deplacement (int) pour le grand echiquier
         * @return valeur du deplacement (int) pour le grand echiquier
         */
        public int valeur() {
            return val;
        }
    }
}












